#include "SymbolTable.h"
#include <iostream>
#include <sstream>
#include "Type.h"

SymbolEntry::SymbolEntry(Type* type, int kind) {
    this->type = type;
    this->kind = kind;
}
//增加了链表操作
bool SymbolEntry::setNext(SymbolEntry* se){
    this->next=se;
    return true;
}

ConstantSymbolEntry::ConstantSymbolEntry(Type* type, int value)
    : SymbolEntry(type, SymbolEntry::CONSTANT) {
    assert(type->isInt());
    this->value = value;
}

ConstantSymbolEntry::ConstantSymbolEntry(Type* type, std::string value)
    : SymbolEntry(type, SymbolEntry::CONSTANT) {
    assert(type->isString());
    this->strValue = value;
}

ConstantSymbolEntry::ConstantSymbolEntry(Type* type)
    : SymbolEntry(type, SymbolEntry::CONSTANT) {
    // assert(type->isArray());
}

int ConstantSymbolEntry::getValue() const {
    assert(type->isInt());
    return value;
}

std::string ConstantSymbolEntry::getStrValue() const {
    assert(type->isString());
    return strValue;
}

std::string ConstantSymbolEntry::toStr() {
    std::ostringstream buffer;
    if (type->isInt())
        buffer << value;
    else if (type->isString())
        buffer << strValue;
    return buffer.str();
}

IdentifierSymbolEntry::IdentifierSymbolEntry(Type* type,
                                             std::string name,
                                             int scope,int paramNo,bool sysf)
    : SymbolEntry(type, SymbolEntry::VARIABLE), name(name) {
    this->scope = scope;
    this->initial = false;
    this->label=-1;
    this->sysf=sysf;
    this->paramNo = paramNo;
}

void IdentifierSymbolEntry::setValue(int value) {
    if (((IntType*)(this->getType()))->isConst()) {
        if (!initial) {
            this->value = value;
            initial = true;
        } else {
            // 需要报错
        }
    } else {
        this->value = value;
    }
}

void IdentifierSymbolEntry::setArrayValue(int* arrayValue) {
    if (((IntType*)(this->getType()))->isConst()) {
        if (!initial) {
            this->arrayValue = arrayValue;
            initial = true;
        } else {
            // 需要报错
        }
    } else {
        this->arrayValue = arrayValue;
    }
}

std::string IdentifierSymbolEntry::toStr() {
    std::ostringstream buffer;
    if (label < 0) {
        if (type->isFunc())
            buffer << '@';
        buffer << name;
    }
    else
        buffer << "%t" << label;
    return buffer.str();
}

TemporarySymbolEntry::TemporarySymbolEntry(Type* type, int label)
    : SymbolEntry(type, SymbolEntry::TEMPORARY) {
    this->label = label;
}

std::string TemporarySymbolEntry::toStr() {
    std::ostringstream buffer;
    buffer << "%t" << label;
    return buffer.str();
}

SymbolTable::SymbolTable() {
    prev = nullptr;
    level = 0;
}

SymbolTable::SymbolTable(SymbolTable* prev) {
    this->prev = prev;
    this->level = prev->level + 1;
}

/*
    Description: lookup the symbol entry of an identifier in the symbol table
    Parameters:
        name: identifier name
    Return: pointer to the symbol entry of the identifier

    hint:
    1. The symbol table is a stack. The top of the stack contains symbol entries
   in the current scope.
    2. Search the entry in the current symbol table at first.
    3. If it's not in the current table, search it in previous ones(along the
   'prev' link).
    4. If you find the entry, return it.
    5. If you can't find it in all symbol tables, return nullptr.
*/
SymbolEntry* SymbolTable::lookup(std::string name) {
    SymbolTable* table = this;
    while (table != nullptr)
        if (table->symbolTable.find(name) != table->symbolTable.end()) {
            return table->symbolTable[name];
        } else {
            table = table->prev;
        }
    return nullptr;
}

SymbolEntry* SymbolTable::lookup_function(std::string name,std::vector<Type*> argu_type) {
    SymbolTable* table = this;
    SymbolEntry* exse;
    bool same_func;
    Type* tmp_func;
    while (table != nullptr){
        if (table->symbolTable.find(name) != table->symbolTable.end()) {
            //同一作用域中只会有一个相应名字
            exse = table->symbolTable[name];
            while(exse){
            //同名定义中如果找到不是函数的，说明重定义
                same_func=true;
                if(!(exse->getType()->isFunc())){
                    fprintf(stderr, "\"%s\" is already defined as a variable\n", name.c_str());
                    assert((exse->getType()->isFunc()));
                }
                else{
                //如果找到了同名函数定义，则检查参数数量和类型
                    tmp_func=exse->getType();
                    if(((FunctionType*)tmp_func)->paramsType.size()!=argu_type.size()){
                        exse=exse->getNext();
                        same_func=false;
                        continue;
                    }
                    for(int i=0;i<((FunctionType*)tmp_func)->paramsType.size();i++){
                        if((((FunctionType*)tmp_func)->paramsType[i])->getKind()!=argu_type[i]->getKind()){
                            same_func=false;
                            break;
                        }
                    }
                    if(same_func){
                        //fprintf(stderr,"call function %s\n",(exse->toStr()).c_str());
                        return exse;
                    }
                    exse=exse->getNext();
                }
            }
        } 
        table = table->prev;
    }
    return nullptr;
}

// install the entry into current symbol table.
void SymbolTable::install(std::string name, SymbolEntry* entry) {
    symbolTable[name] = entry;
}

int SymbolTable::counter = 0;
static SymbolTable t;
SymbolTable* identifiers = &t;
SymbolTable* globals = &t;
